<?php
/**
 * Unity PC 端素材制作软件 查询单体妆容素材
 *
 * Author: Zeon
 * Date: 2018/4/2
 * Created by Panxsoft.
 */

namespace App\Http\Controllers\PC\CustomerStore;

use App\Http\Controllers\ApiController;
use App\Http\Requests\PC\CustomerStore\Asset\AssetIndexRequest;
use App\Http\Requests\PC\CustomerStore\Asset\AssetStoreRequest;
use App\Http\Requests\PC\CustomerStore\Asset\AssetUpdateRequest;
use App\Models\Customer\Asset;
use App\Models\Panx\Product;
use App\Services\Repositories\AssetRepository;
use App\Services\Utils\Transaction;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection as BaseCollection;
use Tests\Feature\PCAssetMaking\AssetControllerTest;

class AssetController extends ApiController
{
    const ROUTES = [
        'index'   => 'pc.asset.index',
        'store'   => 'pc.asset.store',
        'update'  => 'pc.asset.update',
        'destroy' => 'pc.asset.destroy',
    ];

    /**
     * 显示/查询所有panx素材
     *
     * @param AssetIndexRequest $request
     *
     * @param int $customer_id
     * @param int $store_id
     * @return \Illuminate\Http\Response
     */
    public function index(AssetIndexRequest $request, int $customer_id, int $store_id)
    {
        /** @var LengthAwarePaginator $assets */
        $assets = (new Asset)
            ->where(compact('customer_id', 'store_id'))
            ->with([
                'products' => $this->withProductsQuery(),
                'products.thumbImage'
            ])
            ->filterCategory($request->category_id)
            ->latest($request->order_by ?? 'created_at')
            ->paginate($request->per_page ?: 15);

        $this->transformAssetProducts($assets->getCollection());

        return $this->response(compact('assets'));
    }

    /**
     * @test
     *
     * @param AssetStoreRequest $request
     * @param int $customer_id
     * @param int $store_id
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function store(AssetStoreRequest $request, int $customer_id, int $store_id)
    {
        $storeData = $this->assembleStoreData($request, $customer_id, $store_id);

        $stored = (new Asset)->create($storeData);

        return $this->response(compact('stored'));
    }

    /**
     * @test
     * @used-by AssetControllerTest::test_pc_asset_update()
     *
     * @param AssetUpdateRequest $request
     * @param int $customer_id
     * @param int $store_id
     * @param int $asset_id
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function update(AssetUpdateRequest $request, int $customer_id, int $store_id, int $asset_id)
    {
        /** @var Asset $asset */
        $asset = (new Asset)->where(compact('customer_id', 'store_id'))
            ->find($asset_id);
        $this->checkItemExist($asset, trans('pc.asset'));

        $updateData = $this->assembleUpdateData($request, $customer_id, $store_id, $asset);

        $updated = $asset->update($updateData);

        return $this->response(compact('updated'));
    }

    /**
     * @param int $customer_id
     * @param int $store_id
     * @param int $asset_id
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function destroy(int $customer_id, int $store_id, int $asset_id)
    {
        /** @var Asset $asset */
        $asset = (new Asset)
            ->where(compact('customer_id', 'store_id'))
            ->find($asset_id);
        $this->checkItemExist($asset, trans('pc.asset'));
    
//        $this->checkAssetRelations($asset);
    
        list($relation_deletes, $deleted) = Transaction::handle(function () use ($asset) {
            // #907
            $relation_deletes = AssetRepository::destroyRelations($asset);
    
            $deleted = $asset->delete();
            
            return [ $relation_deletes, $deleted ];
        });

        return $this->response(compact('deleted', 'relation_deletes'));
    }

    /**
     * @param AssetUpdateRequest $request
     * @param int $customer_id
     * @param int $store_id
     * @param Asset $asset
     *
     * @return array
     * @throws \Exception
     */
    protected function assembleUpdateData(AssetUpdateRequest $request,
                                          int $customer_id,
                                          int $store_id,
                                          Asset $asset): array
    {
        $model_xml = (new Asset)->uploadFileToUrl(
            $request->model_xml, $request->bos_dir, $request->keep_name
        );

        $updateData = [
            'customer_id' => $customer_id,
            'store_id'    => $store_id,
            'code'        => $request->code,
            'model_xml'   => $model_xml,
            'category_id' => $request->category_id,
            'version'     => $asset->version + 1
        ];

        return $updateData;
    }

    /**
     * @param AssetStoreRequest $request
     * @param int $customer_id
     * @param int $store_id
     *
     * @return array
     * @throws \Exception
     */
    protected function assembleStoreData(AssetStoreRequest $request, int $customer_id, int $store_id): array
    {
        $model_xml = (new Asset)->uploadFileToUrl(
            $request->model_xml, $request->bos_dir, $request->keep_name
        );

        $storeData = [
            'code'        => $request->code,
            'model_xml'   => $model_xml,
            'customer_id' => $customer_id,
            'category_id' => $request->category_id,
            'store_id'    => $store_id,
        ];

        if ($request->has('version')) {
            $storeData['version'] = $request->version;
        }

        return $storeData;
    }
    
    /**
     * #907 - 暂不检查，关联直接清除
     *
     * @param $asset
     */
    private function checkAssetRelations(Asset $asset): void
    {
        $product = $asset->products()->first();
            $this->checkUnless($product, trans('pc.product_asset'));
        
        $pack = $asset->packs()->first();
            $this->checkUnless($pack, trans('pc.pack_asset'));
        
        $pivot_product = $asset->assetPivotProducts()->first();
            $this->checkUnless($pivot_product, trans('pc.pack_asset'));
    }

    /**
     * @return \Closure
     */
    private function withProductsQuery()
    {
        return function (HasMany $hasMany) {
            $hasMany->select(['id', 'name', 'title', 'asset_id']);
        };
    }

    /**
     * @param Collection|BaseCollection $assets
     */
    private function transformAssetProducts(BaseCollection $assets)
    {
        $assets->each(function (Asset $asset) {
            $asset->products->each(function (Product $product) {
                $product->append('thumb_url');
                $product->makeHidden(['thumbImage']);
            });
        });
    }
}
